package com.example.dmservice.exceloutput.service;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.teaopenapi.models.Config;
import com.example.dmcommom.*;
import com.example.dmdomain.UseLogRepository;
import com.example.dmdomain.UserRepository;
import com.example.dmdomain.entity.UseLog;
import com.example.dmdomain.entity.User;
import com.example.dmservice.auth.AuthService;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@Configuration
public class UserServiceImpl implements UserService{
    public static final String VERIFY_CODE = "login:verify_code:";

    public static final String ACCESS_KEY_ID = "LTAI5tJWGtDQjy9ZRGYA4jD6";

    public static final String ACCESS_KEY_SECRET = "4cD7KbZMtbynqSYkgima71Oud87eQf";

    public static final String TEMPLATE_CODE = "SMS_296335865";

    public static final String END_POINT = "dysmsapi.aliyuncs.com";

    @Value("${account.register.create}")
    private boolean REGISTER_ENABLE;
    
    @Value("${account.type.internal}")
    private int ACCOUNT_TYPE_INTERNAL;

    @Value("${account.type.default}")
    private int ACCOUNT_TYPE_DEFAULT;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UseLogRepository useLogRepository;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private RedisUtils redisUtils;

    public String register(String phone, String smsCode, String ip) throws ParseException {

        //1,先查验证码
        String smsCodeKey = VERIFY_CODE + phone;
        String verifyCode = redisTemplate.opsForValue().get(smsCodeKey);
        if (StringUtils.isEmpty(verifyCode)) {
            return "短信验证码不存在或已过期";
        }
        if (!smsCode.equals(verifyCode)) {
            return "短信验证码错误";
        }
        //清理验证码
        if (Boolean.TRUE.equals(redisTemplate.hasKey(smsCodeKey))) {
            redisTemplate.delete(smsCodeKey);
        }
        //2,再判断是否第一次登录
        User loginUser = userRepository.findUsersByPhone(phone);

        if (loginUser == null) {
            if (REGISTER_ENABLE) {
                loginUser = doRegisterNoAuth(phone);
            } else {
                throw new AuthException("联系管理员进行注册");
            }
        }
        if (!loginUser.getAccountType().equals(ACCOUNT_TYPE_INTERNAL)) {
            AuthService authService = SpringBeanHelper.getBeanOrThrow(AuthService.class);
            boolean auth;
            try {
                auth = authService.checkPermission(loginUser);
            } catch (Exception e) {
                throw new AuthException("请联系管理员进行授权");
            }
            if (!auth) {
                throw new AuthException("请联系管理员进行授权");
            }
        }

        //3,修改登录日志数据表
        UseLog useLog = new UseLog();
        useLog.setUseLogId(String.valueOf(System.currentTimeMillis()));
        useLog.setUserPhone(phone);
        Date loginDay = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        String loginTime = sdf.format(loginDay);
        useLog.setLoginTime(sdf.parse(loginTime));
        useLog.setLoginIp(ip);
        useLogRepository.save(useLog);

        String token = Md5TokenGenerator.generate(phone, verifyCode);
        String tokenKey = "TOKEN_EXPIRE_" + phone;
        //如果是“记住我”，则Token有效期是7天，反之则是24个小时
        redisUtils.add(tokenKey, token,  24, TimeUnit.HOURS);
        User loginUser1 = userRepository.findUsersByPhone(phone);
        log.info("==========================账号登录:{}",phone);
        return loginUser1.getUserId();
    }

    private User doRegister(String phone, int AccountType) throws ParseException {
        User user = new User();
        user.setPhone(phone);

        user.setUserId(UUID.randomUUID().toString());
        user.setRegisterType("手机验证码");

        String defaultPassword = "123456";
        String md5Pwd = IdGenerator.md5Id(defaultPassword);
        user.setPassword(md5Pwd);
        user.setAccountType(AccountType);

        Date day = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        String time = sdf.format(day);
        user.setCreateTime(sdf.parse(time));
        userRepository.save(user);
        log.info("==========================账号首次注册登录");
        return user;
    }

    public User doRegisterNoAuth(String phone) throws ParseException {
        return doRegister(phone,ACCOUNT_TYPE_DEFAULT);
    }

    @Override
    public String getSmsCode(String phone) throws Exception {

        //生成验证码
        String smsVerifyCode = getSmsVerifyCode();
        String smsCodeKey = VERIFY_CODE + phone;

        //查找redis
        String existedSmsCode = redisTemplate.opsForValue().get(smsCodeKey);
        //如果验证码已经存在
        if (!StringUtils.isEmpty(existedSmsCode)) {
            Long expireTime = redisTemplate.opsForValue().getOperations().getExpire(smsCodeKey);
            long lastTime = 60 * 3 - expireTime;
            //三分钟内验证码有效，1分钟到3分钟之间，用户可以继续输入验证码，也可以重新获取验证码，新的验证码将覆盖旧的
            if(lastTime > 60 && expireTime >0){
                //调用第三方平台发短信，只有短信发送成功了，才能将短信验证码保存到redis
                Config config = new Config()
                        //这里修改为我们上面生成自己的AccessKey ID
                        .setAccessKeyId(ACCESS_KEY_ID)
                        //这里修改为我们上面生成自己的AccessKey Secret
                        .setAccessKeySecret(ACCESS_KEY_SECRET);
                // 访问的域名
                config.endpoint = END_POINT;
                com.aliyun.dysmsapi20170525.Client client = new Client(config);
                SendSmsRequest sendSmsRequest = new SendSmsRequest()
                        .setSignName("达卯智能")//短信签名
                        .setTemplateCode(TEMPLATE_CODE)//短信模板
                        .setPhoneNumbers(phone)//这里填写接受短信的手机号码
                        .setTemplateParam("{\"code\":\""+smsVerifyCode+"\"}");//验证码
                // 复制代码运行请自行打印 API 的返回值
                client.sendSms(sendSmsRequest);
                redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, 60 * 3, TimeUnit.SECONDS);
            }
            //一分钟之内不得多次获取验证码
            if(lastTime < 60){
//                throw new RuntimeException("操作过于频繁，请一分钟之后再次点击发送");
                return "获取验证码操作太频繁，请稍后再试";
            }
        }else {
            Config config = new Config()
                    //这里修改为我们上面生成自己的AccessKey ID
                    .setAccessKeyId(ACCESS_KEY_ID)
                    //这里修改为我们上面生成自己的AccessKey Secret
                    .setAccessKeySecret(ACCESS_KEY_SECRET);
            // 访问的域名
            config.endpoint = END_POINT;
            com.aliyun.dysmsapi20170525.Client client = new Client(config);
            SendSmsRequest sendSmsRequest = new SendSmsRequest()
                    .setSignName("达卯智能")//短信签名
                    .setTemplateCode(TEMPLATE_CODE)//短信模板
                    .setPhoneNumbers(phone)//这里填写接受短信的手机号码
                    .setTemplateParam("{\"code\":\""+smsVerifyCode+"\"}");//验证码
            // 复制代码运行请自行打印 API 的返回值
            client.sendSms(sendSmsRequest);
            redisTemplate.opsForValue().set(smsCodeKey, smsVerifyCode, 60 * 3, TimeUnit.SECONDS);
        }
        return smsVerifyCode;
    }

    public static String getSmsVerifyCode() {
        Random random = new Random();
        String code = "";
        for (int i = 0; i < 6; i++) {
            int rand = random.nextInt(10);
            code += rand;
        }
        return code;
    }

    public ResponseResult logOut(String phone, HttpServletRequest request) throws ParseException {
        String tokenKey = "TOKEN_EXPIRE_" + phone;
        //删除redis的token
        redisUtils.delete(tokenKey);
//        String ip = request.getRemoteAddr();
        //根据手机号查找日志表，增加登出时间
        Date logoutDay = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        String logoutTime = sdf.format(logoutDay);
        Date date = sdf.parse(logoutTime);
        useLogRepository.updateLogoutTime(phone, date);

        return ResponseResult.success("退出成功");
    }

    /**
     * 生成带参数的二维码的ticket
     * @param expire_seconds
     * @param scene_str
     * @return
     * @throws Exception
     */
    @Override
    public String createTempStrTicket(String expire_seconds,String scene_str) throws Exception {
        String access_token = this.getAccessToken();
        String url = WechatConfig.CREATE_TICKET_PATH;
        url = url.replaceAll("ACCESS_TOKEN",access_token);

        Map<String,String> strMap = new HashMap<String,String>();
        strMap.put("scene_str",scene_str);

        Map<String,Map<String,String>> mapMap = new HashMap<String,Map<String,String>>();
        mapMap.put("scene", strMap);

        Map<String,Object> paramsMap = new HashMap<String,Object>();
        paramsMap.put("expire_seconds", expire_seconds);
        paramsMap.put("action_name", WechatConfig.QR_STR_SCENE);
        paramsMap.put("action_info", mapMap);
        String data = new Gson().toJson(paramsMap);
        // 发送请求
        Map<String, Object> map = HttpClient.sendPost(url, data);
        String ticket = (String) map.get("ticket");

        return ticket==null?null:ticket;
    }

    /**
     * 获取access_tocken GET方法
     * @return
     */
    @Override
    public String getAccessToken() {
        String url = WechatConfig.ACCESS_TOKEN_URL;
        url = url.replaceAll("APPID", WechatConfig.APPID);
        url = url.replaceAll("SECRET", WechatConfig.SECRET);
        Map<String, Object> map = HttpClient.sendGet(url);
        return map.get("access_token").toString();
    }


    /**
     * 获取二维码ticket后，通过ticket换取二维码图片展示
     * @param ticket
     * @return
     */
    @Override
    public String showqrcode(String ticket) {
        String qrcodeUrl = WechatConfig.SHOWQR_CODE_PATH;
        try {
            String encode = URLEncoder.encode(ticket, "utf-8");
            qrcodeUrl = qrcodeUrl.replaceAll("TICKET",encode);
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        return qrcodeUrl;
    }

    @Override
    public WechatUser getWechatUser(String scene_str) {
        WechatUser wechatUser = new WechatUser();
        return wechatUser;
    }


    @Override
    public String checkPermission() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userId = request.getHeader("Authorization");
        User user = userRepository.findUsersByUserID(userId);
        if (user == null) {
            return "用户权限校验失败";
        }
        return "成功";
    }
}
